﻿@using System.IO.Ports;
@using zy_simu.Data
@inject SimuCfg emu_cfg
@inject DeviceSnap dev_snap

<style>
    #div-hardware-panel {
    position: relative;
    border: 1px solid #000;
    border-radius: 5px;
    /*width: calc(var(--panel-width)*1.2);*/
    /*height: calc(var(--panel-height)*2);*/
    /*overflow: hidden;*/
    margin: 5px;
    padding: 5px;
    }

    .btn {
    --bs-btn-padding-x: .2rem;
    }
</style>

<div class="row" style="margin-left: 0px">
    <div class="col-5"> <h5>设备模拟控制台</h5> </div>
    <div class="col-3"><Checkbox TValue="bool" @bind-Value="@simu_peripheral" ShowAfterLabel="true" DisplayText="仿真外设" Color="Color.Danger" /></div>
    <div class="col-4"><Checkbox TValue="bool" @bind-Value="@emu_cfg.factory_reset" ShowAfterLabel="true" DisplayText="启动时恢复出厂设置" Color="Color.Danger" /></div>
</div>

<div id="div-hardware-panel">
    <div class="row" style="margin-left: 0px; font-size: 18px">
        <div class="col-2"> <p>IO状态：</p> </div>
        <div class="col-1"> <i class="fas fa-snowflake" style="@GetOutputIconStyle(dev_snap.gpio.motor)"></i> </div>
        <div class="col-1"> <i class="fas fa-fan" style="@GetOutputIconStyle(dev_snap.gpio.fan)"></i> </div>
        <div class="col-1"> <i class="fas fa-mug-hot" style="@GetOutputIconStyle(dev_snap.gpio.heater)"></i> </div>
        <div class="col-1"> <i class="fas fa-cloud-rain" style="@GetOutputIconStyle(dev_snap.gpio.melt)"></i> </div>
        <div class="col-1"> <i class="fas fa-lightbulb" style="@GetOutputIconStyle(dev_snap.gpio.light)"></i> </div>
        <div class="col-1"> <i class="fas fa-power-off" style="@GetOutputIconStyle(dev_snap.gpio.power_led)"></i> </div>
    </div>
    <div class="row" style="margin-left: 0px; font-size: 18px">
        <div class="col-2"> <p>fun状态：</p> </div>
        <div class="col-2"> <i class="fas fa-wave-square"></i> @dev_snap.pwm[0].ToString() </div>
        <div class="col-2"> <i class="fas fa-wave-square"></i> @dev_snap.pwm[1].ToString() </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-3"><Checkbox TValue="bool" @bind-Value="@emu_cfg.pow" ShowAfterLabel="true" DisplayText="12V市电" Color="Color.Danger" /></div>
        <div class="col-3"><Checkbox TValue="bool" @bind-Value="@emu_cfg.battery" ShowAfterLabel="true" DisplayText="电池" /></div>
        <div class="col-3"><Checkbox TValue="bool" @bind-Value="@emu_cfg.sensor1" ShowAfterLabel=" true" DisplayText="温度传感器1" /></div>
        <div class="col-3"><Checkbox TValue="bool" @bind-Value="@emu_cfg.sensor2" ShowAfterLabel=" true" DisplayText="温度传感器2" /></div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.local_switch" OnColor="Color.Danger" OnText="控制器开关" OffText="控制器开关" ShowInnerText="true"></Switch> </div>
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.remote_switch" OnColor="Color.Danger" OnText="远程开关" OffText="远程开关" ShowInnerText="true"></Switch> </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-4"><Checkbox TValue="bool" @bind-Value="@emu_cfg.door_polarity" ShowAfterLabel="true" DisplayText="门磁极性" /></div>
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.door1" OnColor="Color.Warning" OnText="门1开" OffText="门1关" ShowInnerText="true" IsDisabled="@(!dev_snap.IsGPIOValid(dev_snap.gpio.det_door1))"></Switch> </div>
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.door2" OnColor="Color.Warning" OnText="门2/防拆开" OffText="门2/防拆关" ShowInnerText="true" IsDisabled="@(!dev_snap.IsGPIOValid(dev_snap.gpio.det_door2))"></Switch> </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.human" OnColor="Color.Warning" OnText="有人" OffText="无人" ShowInnerText="true" IsDisabled="@(!dev_snap.IsGPIOValid(dev_snap.gpio.det_human))"></Switch> </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-4"> <Switch @bind-Value="@emu_cfg.wifi" OnColor="Color.Warning" OnText="wifi信号" OffText="wifi信号" ShowInnerText="true"></Switch> </div>
    </div>


    @* 箱体温度模拟 *@
    <div class="row g-2 form-inline" style="display: flex; align-items: center; vertical-align: middle; margin: 2px">
        <div class="col-12 col-sm-2" style="display: flex; align-items: center; margin-right: 0px; padding-right: 0px"><p style="margin: 0;">箱体温度</p></div>
        <div class="col-12 col-sm-4"><BootstrapInputNumber @bind-Value="@emu_cfg.box_tem" DisplayText="箱体温度" IsSelectAllTextOnFocus="true" Color="Color.Warning" Step="1" Min="-100" Max="100" FormatString="#.#" /></div>
        <div class="col-12 col-sm-4"><Select Color="Color.Warning" Items="BoxTemVelocityItems" @bind-Value="emu_cfg.BoxTemVelocity"></Select></div>
    </div>
    @* 蒸发器温度模拟 *@
    <div class="row g-2 form-inline" style="display: flex; align-items: center; vertical-align: middle; margin: 2px">
        <div class="col-12 col-sm-2" style="display: flex; align-items: center; margin-right: 0px; padding-right: 0px"><p style="margin: 0;">蒸发器温度</p></div>
        <div class="col-12 col-sm-4"><BootstrapInputNumber @bind-Value="@emu_cfg.defrost_tem" DisplayText="蒸发器温度" IsSelectAllTextOnFocus="true" Color="Color.Warning" Step="1" Min="-100" Max="100" FormatString="#.#" /></div>
        <div class="col-12 col-sm-4"><Select Color="Color.Warning" Items="DefrostVelocityItems" @bind-Value="emu_cfg.DefrostVelocity"></Select></div>
    </div>


    <div class="row" style="margin-left: 0px">
        <div class="col-2" style="margin-right: 0px; padding-right: 0px">
            <p>压机模拟</p>
        </div>
        <div class="col-4">
            <Select Color="Color.Warning" Items="CompVelocityItems" @bind-Value="emu_cfg.CompVelocity"></Select>
        </div>
    </div>
    <div class="row" style="margin-left: 0px">
        <div class="col-2" style="margin-right: 0px; padding-right: 0px"><p>4G信号</p></div>
        <div class="col-4"><BootstrapInputNumber @bind-Value="@emu_cfg._4g" IsSelectAllTextOnFocus="true" Color="Color.Warning" Step="1" Min="0" Max="31" /></div>
        <div class="col-2" style="margin-right: 0px; padding-right: 0px"><p>电池电压</p></div>
        <div class="col-4"><BootstrapInputNumber @bind-Value="@emu_cfg.vbatt" IsSelectAllTextOnFocus="true" Color="Color.Warning" Step="1" Min="-1" Max="4.5" FormatString="#.#" /></div>
    </div>
</div>



@code {
    private bool simu_peripheral = false;
    private bool io_motor_state = false;
    private bool io_fan_state = false;
    private bool io_heater_state = false;
    private bool io_melt_state = false;
    private bool io_light_state = false;
    private bool io_pow_led_state = false;
    private byte pwm1 = 0;
    private byte pwm2 = 0;


    // 模拟压机降温速率
    //private string CompVelocity = "0";
    private IEnumerable<SelectedItem> CompVelocityItems { get; set; } = new[]
    {
        new SelectedItem ("0", "关闭动态模拟") { Active = true },
        new SelectedItem ("30", "30秒降1度"),
        new SelectedItem ("60", "60秒降1度"),
        new SelectedItem ("120", "120秒降1度"),
        new SelectedItem ("300", "300秒降1度"),
        new SelectedItem ("600", "600秒降1度"),
    };
    // 模拟箱体升温速率
    //private string BoxTemVelocity = "0";
    private IEnumerable<SelectedItem> BoxTemVelocityItems { get; set; } = new[]
    {
        new SelectedItem ("0", "关闭动态模拟") { Active = true },
        new SelectedItem ("60", "60秒升1度"),
        new SelectedItem ("120", "120秒升1度"),
        new SelectedItem ("300", "300秒升1度"),
        new SelectedItem ("600", "600秒升1度"),
        new SelectedItem ("1800", "1800秒升1度"),
    };
    // 模拟化霜蒸发器升温速率
    //private string BoxTemVelocity = "0";
    private IEnumerable<SelectedItem> DefrostVelocityItems { get; set; } = new[]
    {
        new SelectedItem ("0", "关闭动态模拟") { Active = true },
        new SelectedItem ("60", "60秒升1度"),
        new SelectedItem ("120", "120秒升1度"),
        new SelectedItem ("300", "300秒升1度"),
        new SelectedItem ("600", "600秒升1度"),
        new SelectedItem ("1800", "1800秒升1度"),
    };

    protected override void OnInitialized()
    {
        if (emu_cfg.m0_mode == "仿真") simu_peripheral = true; // 模拟器选中，主动模拟
        base.OnInitialized();
    }

    private static int simu_battery_plus = 0;

    private string GetOutputIconStyle(byte gpio)
    {
        if(!dev_snap.IsGPIOValid(gpio)) return "color: dimgrey";
        if (dev_snap.ReadGPIO(gpio)) return "color: red";
        else return "color: black";
    }

    private ushort GetSimuNTCValue(float tem, bool sensor)
    {
        if (!sensor) return 3250; // 传感器错误
                                  // NTC1 采样电压
        uint idx = (uint)(tem + DevPreDef.tem_om_table_base); 
        if (idx > DevPreDef.tem_om_table.Length) idx = (uint)DevPreDef.tem_om_table.Length; // 限定不要溢出, TODOOO 重新考虑溢出计算为传感器错
        int span_10x = emu_cfg.box_tem > 0 ? (int)((emu_cfg.box_tem * 10 + 0.5)) % 10 : (int)((emu_cfg.box_tem * 10 - 0.5)) % 10; // 正负四舍五入
        if (span_10x < 0)
            span_10x += 10;
        uint om = DevPreDef.tem_om_table[idx] - (DevPreDef.tem_om_table[idx] - DevPreDef.tem_om_table[idx + 1]) * (uint)span_10x / 10;
        return (ushort)(DevPreDef.ref_voltage * om / (10000 + om));
    }
    public void SimuInput(DeviceSnap dbg)
    {
        if (simu_peripheral) // 模拟器选中，主动模拟输入
        {
            // update environment temperature
            UpdateBoxTem(dbg.st_tb.comp_on_timer, dbg.st_tb.comp_off_timer);
            // 参考电压
            dbg.adc[DevPreDef.ADC_CHN_VREF] = (ushort)DevPreDef.ref_voltage;
            // NTC1/NTC2 采样电压
            dbg.adc[DevPreDef.ADC_CHN_NTC1] = GetSimuNTCValue(emu_cfg.box_tem, emu_cfg.sensor1);
            // dbg.adc[DevPreDef.ADC_CHN_NTC2] = GetSimuNTCValue(emu_cfg.defrost_tem, emu_cfg.sensor2);
            // 电池采样电压
            dbg.adc[DevPreDef.ADC_CHN_VBAT] = (ushort)(emu_cfg.vbatt * 1000 * 510 / (510 + 147) + 0.5);

            // GPIO door 门磁开关接地, doP参数缺省0：开门时开关断开，关门时开关闭合
            if (emu_cfg.door_polarity)
                dev_snap.WriteGPIO(dev_snap.gpio.det_door1, !emu_cfg.door1);
            else
                dev_snap.WriteGPIO(dev_snap.gpio.det_door1, emu_cfg.door1);
            dev_snap.WriteGPIO(dev_snap.gpio.det_door2, emu_cfg.door2);
            // 人流量
            dev_snap.WriteGPIO(dev_snap.gpio.det_human, emu_cfg.human);

            // 系统开关
            dev_snap.WriteGPIO(dev_snap.gpio.det_sys_switch, !emu_cfg.local_switch);
            // 市电
            dev_snap.WriteGPIO(dev_snap.gpio.det_12v, emu_cfg.pow);

            // 电池
            simu_battery_plus++;
            if (emu_cfg.battery) // 模拟有电池
                dev_snap.WriteGPIO(dev_snap.gpio.batt_chrg, true);
            else // 模拟无电池, 充电芯片TC4056A 没有电池250ms一个脉冲
            {
                if (simu_battery_plus % 2 == 0) dev_snap.WriteGPIO(dev_snap.gpio.batt_chrg, true);
                else dev_snap.WriteGPIO(dev_snap.gpio.batt_chrg, false);
            }

            // cat1 network
            dev_snap.Cat1Command($"4g={emu_cfg._4g}\n");
        }
    }
    public void SimuOutput(DeviceSnap dbg)
    {
        if(emu_cfg.m0_mode == "外设") {// 挂真实外设，同步外设输出
            if (dev_snap.IsGPIOValid(dev_snap.gpio.det_door1))
            {
                if (emu_cfg.door_polarity)
                    emu_cfg.door1 = !dev_snap.ReadGPIO(dev_snap.gpio.det_door1);
                else
                    emu_cfg.door1 = dev_snap.ReadGPIO(dev_snap.gpio.det_door1);
            }
            // 追踪系统开关
            if (dev_snap.IsGPIOValid(dev_snap.gpio.det_sys_switch))
                emu_cfg.local_switch = !dev_snap.ReadGPIO(dev_snap.gpio.det_sys_switch);
            // 追踪电源
            if (dev_snap.IsGPIOValid(dev_snap.gpio.det_12v))
                emu_cfg.pow = dev_snap.ReadGPIO(dev_snap.gpio.det_12v);
            // 追踪传感器
            emu_cfg.sensor1 = ((dbg.st_tb.alarm & (byte)(ZqAlarmFlag.ZQ_ALARM_SENSOR)) == 0);
            emu_cfg.sensor2 = ((dbg.st_tb.alarm & (byte)(ZqAlarmFlag.ZQ_ALARM_DEFROST_SENSOR)) == 0);
        }
        // 记录压机/风机/加热器等状态
        bool motor_state = io_motor_state;
        bool fan_state = io_fan_state;
        bool heater_state = io_heater_state;
        bool melt_state = io_melt_state;
        bool light_state = io_light_state;
        bool pow_led_state = io_pow_led_state;
        io_motor_state = (dev_snap.IsGPIOValid(dev_snap.gpio.motor)) ? dev_snap.ReadGPIO(dev_snap.gpio.motor) : false;
        io_fan_state = (dev_snap.IsGPIOValid(dev_snap.gpio.fan)) ? dev_snap.ReadGPIO(dev_snap.gpio.fan) : false;
        io_heater_state = (dev_snap.IsGPIOValid(dev_snap.gpio.heater)) ? dev_snap.ReadGPIO(dev_snap.gpio.heater) : false;
        io_melt_state = (dev_snap.IsGPIOValid(dev_snap.gpio.melt)) ? dev_snap.ReadGPIO(dev_snap.gpio.melt) : false;
        io_light_state = (dev_snap.IsGPIOValid(dev_snap.gpio.light)) ? dev_snap.ReadGPIO(dev_snap.gpio.light) : false;
        io_pow_led_state = (dev_snap.IsGPIOValid(dev_snap.gpio.power_led)) ? dev_snap.ReadGPIO(dev_snap.gpio.power_led) : false;
        bool pwm_changed = false;
        if (pwm1 != dev_snap.pwm[0] || pwm2 != dev_snap.pwm[1])
        {
            pwm_changed = true;
            pwm1 = dev_snap.pwm[0];
            pwm2 = dev_snap.pwm[1];
        }

        if (io_motor_state != motor_state 
            || io_fan_state != fan_state 
            || io_heater_state != heater_state 
            || io_melt_state != melt_state 
            || io_light_state != light_state 
            || io_pow_led_state != pow_led_state
            || pwm_changed) // 刷新界面
            InvokeAsync(StateHasChanged).Wait();
        // InvokeAsync(StateHasChanged).Wait();
    }
    public bool GetCat1Status(DeviceSnap dbg)
    {
        return dev_snap.ReadGPIO(dev_snap.gpio.cat1_en);
    }
    private int last_comp_on_timer = 0;
    private int last_comp_off_timer = 0;
    private void UpdateBoxTem(int comp_on_timer, int comp_off_timer)
    {
        int cv = int.Parse(emu_cfg.CompVelocity);
        int bv = int.Parse(emu_cfg.BoxTemVelocity);
        int dv = int.Parse(emu_cfg.DefrostVelocity);

        float tem = emu_cfg.box_tem;
        if (comp_on_timer == 0) last_comp_on_timer = 0;
        if (comp_off_timer == 0) last_comp_off_timer = 0;
        if (cv != 0 && comp_on_timer > 0)
        {
            if ((comp_on_timer - last_comp_on_timer) >= (cv / 10))
            {
                tem -= 0.1f;
                last_comp_on_timer = comp_on_timer;
            }
        }
        else if (bv != 0 && comp_off_timer > 0)
        {
            if ((comp_off_timer - last_comp_off_timer) >= (bv / 10))
            {
                tem += 0.1f;
                last_comp_off_timer = comp_off_timer;
            }
        }
        if (tem != emu_cfg.box_tem)
        {
            emu_cfg.box_tem = tem;
            InvokeAsync(StateHasChanged);
        }

    }
    public void Start()
    {
        // emu_cfg.pow = true;
        InvokeAsync(StateHasChanged);
    }
    public void Stop()
    {
        // emu_cfg.pow = false;
        InvokeAsync(StateHasChanged);
    }
    public Dictionary<string, string> Snap()
    {
        Dictionary<string, string> dict = new Dictionary<string, string>();
        dict["压机"] = io_motor_state ? "1" : "0";
        dict["风机"] = io_fan_state ? "1" : "0";
        dict["制热"] = io_heater_state ? "1" : "0";
        dict["主动化霜"] = io_melt_state ? "1" : "0";
        dict["灯"] = io_light_state ? "1" : "0";
        return dict;
    }

}

@*
    电源开关, 本地控制器开关,
    箱体温度, 电池电压(-1 - 无电池), 门开关, 人感(随机n人/分钟)
    如果接cat1, 就灰掉: 远端开关, 4g信号强度, wifi信号有无
    外接灯,
*@